package com.dycs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.dimpt.unigw.token.TokenService;
import com.dycs.entity.User;
import com.dycs.entity.UserToken;
import com.dycs.mapper.UserMapper;
import com.dycs.mapper.UserTokenMapper;
import com.dycs.service.UserTokenService;
import com.dycs.utils.SMSUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.security.MessageDigest;
import java.sql.Timestamp;
import java.util.Base64;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class UserTokenServiceImpl implements UserTokenService {

    private static final String ENCODING = "UTF-8";

    @Autowired(required = false)
    private UserMapper userMapper;

    @Autowired(required = false)
    private UserTokenMapper userTokenMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public String createToken(String username, String password) {

        ValueOperations ops = redisTemplate.opsForValue();
        int count;

        if (ops.get(username) == null) {
            count = 0;
        } else {
            count = (int) ops.get(username);
        }

        if (count > 4) {
            return "用户错误次数过多，请半小时后再试";
        }

        String newPassword, decrypt;

        try {
            decrypt = TokenService.decrypt(Base64.getDecoder().decode(password));

            if (isNotValid(username, decrypt)) {
                ops.set(username, count + 1);
                redisTemplate.expire(username, 30 * 60, TimeUnit.SECONDS);
                return "用户名或密码格式有误";
            }

            newPassword = Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(decrypt.getBytes(ENCODING)));
            System.out.println(newPassword);
        } catch (Exception e) {
            return "密码处理出错";
        }

        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username", username).eq("password", newPassword);
        String message;

        User user = userMapper.selectOne(userQueryWrapper);

        if (user == null) {
            ops.set(username, count + 1);
            redisTemplate.expire(username, 30 * 60, TimeUnit.SECONDS);
            message = "用户名或密码有误";
        } else {

            if (isTelephone(user.getMobilephone())) {
                if (!isValid(user.getMobilephone())) {
                    return "验证码过期或有误";
                }
            } else {
                return "预留手机号码有误";
            }

            if (!isPower(decrypt)) {
                message = "密码强度不足，请修改密码";
            } else {
                UserToken userToken = TokenService.generateTokenWithUsernameAndPassword(username, decrypt);
                userToken.setUid(user.getId());
                userToken.setTokentype(0);
//                System.out.println(userToken);

                int insert = userTokenMapper.insertOrUpdate(userToken);

                System.out.println(insert);
                if (insert == 1) {
                    message = "用户token创建成功";
                    ops.set(userToken.getToken(), userToken.getExpiredtime());
//                    System.out.println("<-------------------------------->");
//                    System.out.println("--------------success-------------");
//                    System.out.println("<-------------------------------->");
                } else if (insert == 2){
                    message = "用户token已存在，有效时间更新";
                    ops.set(userToken.getToken(), userToken.getExpiredtime());
//                    System.out.println("<-------------------------------->");
//                    System.out.println("--------------success-------------");
//                    System.out.println("<-------------------------------->");
                } else {
                    message = "用户token创建失败，请稍后再试";
//                    System.out.println("<-------------------------------->");
//                    System.out.println("---------------error--------------");
//                    System.out.println("<-------------------------------->");
                }
            }
        }

        return message;
    }

    @Override
    public String updateToken(String token) {

        String uid = TokenService.getUid(token);
        String message;

        if (uid == null || uid == "") {
            message = "无效的token信息";
        } else {

            ValueOperations ops = redisTemplate.opsForValue();
            Object o = ops.get(token);

            if (o == null) {

                QueryWrapper<UserToken> userTokenQueryWrapper = new QueryWrapper<>();
                userTokenQueryWrapper.eq("token", token);

                UserToken userToken = userTokenMapper.selectOne(userTokenQueryWrapper);

                if (userToken == null) {
                    message = "token不存在";
                } else {

                    ops.set(token, userToken.getExpiredtime());

                    long nowMills = System.currentTimeMillis(), time = userToken.getExpiredtime().getTime(), subTime = time - nowMills;

                    if (subTime < 0) {
                        message = "token已过期，请重新登录";
                    } else {
                        if (userToken.getTokentype() == 0) {

                            if (subTime < 30) {

                                UpdateWrapper<UserToken> userTokenUpdateWrapper = new UpdateWrapper<>();
                                userTokenUpdateWrapper.set("expiredtime", new Timestamp(nowMills + 30 * 60 * 1000));

                                int update = userTokenMapper.update(userToken, userTokenUpdateWrapper);

                                if (update == 1) {
                                    message = "token更新成功";
                                    ops.set(token, new Timestamp(nowMills + 30 * 60 * 1000));
//                                    System.out.println("<-------------------------------->");
//                                    System.out.println("--------------success-------------");
//                                    System.out.println("<-------------------------------->");
                                } else {
                                    message = "token更新失败";
//                                    System.out.println("<-------------------------------->");
//                                    System.out.println("---------------error--------------");
//                                    System.out.println("<-------------------------------->");
                                }
                            } else {
                                message = "token无须更新";
                            }
                        } else {
                            message = "token无须更新";
                        }
                    }

                }

            } else {

                System.out.println("--------------redis---------------");

                Timestamp timestamp = (Timestamp) o;
                long time = timestamp.getTime(), nowMills = System.currentTimeMillis(), subTime = time - nowMills;

                if (subTime < 0) {
                    message = "token已过期，请重新登录";
                    redisTemplate.delete(token);
                } else {

                    if (subTime < 30) {

                        ops.set(token, new Timestamp(nowMills + 30 * 60 * 1000));
                        message = "token更新成功";

                    } else {
                        message = "token无须更新";
                    }

                }
            }
        }
        return message;
    }

    @Override
    @Scheduled(fixedRate = 24 * 60 * 60 * 1000)
    public void deleteOverTimeToken() {

        long nowMills = System.currentTimeMillis();
        QueryWrapper<UserToken> userTokenQueryWrapper = new QueryWrapper<>();

        Timestamp timestamp = new Timestamp(nowMills);
        userTokenQueryWrapper.lt("expiredtime", timestamp);
        int delete = userTokenMapper.delete(userTokenQueryWrapper);

        System.out.println(delete);
    }

    public boolean isPower(String password) {
//                        密码强度：必须包括数字、大小写字母和特殊字符，长度在8-16位。
        String regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,16}$";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(password);

        if (matcher.matches()) {
            return true;
        }

        return false;
    }

    public boolean isNotValid(String username, String password) {

        String regex1 = "^[a-zA-Z0-9_-]{3,20}$", regex2 = "^[A-Za-z\\d$@$!%*?&]{8,16}$";

        Pattern pattern1 = Pattern.compile(regex1), pattern2 = Pattern.compile(regex2);
        Matcher matcher1 = pattern1.matcher(username), matcher2 = pattern2.matcher(password);

        if (matcher1.matches() && matcher2.matches()) {
            return false;
        }

        return true;
    }

    @Override
    public boolean isValid(String telephone) {

        double random = Math.random();
        String value = String.valueOf(random), valid = value.substring(value.length() - 6, value.length());
        ValueOperations<Object, String> ops = redisTemplate.opsForValue();

        ops.set(telephone, valid);
        redisTemplate.expire(telephone, 60, TimeUnit.SECONDS);
        SMSUtils.sendMessage("阿里云短信测试", "SMS_154950909", telephone, valid);

        Scanner scanner = new Scanner(System.in);

        if (scanner.hasNext()) {
            valid = ops.get(telephone);
            if (valid != null && valid.equals(scanner.next())) {
                scanner.close();
                return true;
            }
        }

        scanner.close();
        return false;
    }

    private boolean isTelephone(String mobile) {

        String regex = "^(?:\\+?86)?1(?:3\\d{3}|5[^4\\D]\\d{2}|8\\d{3}|7(?:[01356789]\\d{2}|4(?:0\\d|1[0-2]|9\\d))|9[189]\\d{2}|6[567]\\d{2}|4(?:[14]0\\d{3}|[68]\\d{4}|[579]\\d{2}))\\d{6}$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(mobile);

        return matcher.matches();
    }
}

